/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
* Copyright (c) 2011 SMUNIX
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation;
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*
* Author: Providence M. Salumu <providence.salumu@smunix.com>
*/


#ifndef AGGREGATOR_HPP__222402
#define AGGREGATOR_HPP__222402

#include <memory>
#include <stdexcept>

#include <boost/current_function.hpp>

namespace smunix
{
  namespace injection
  {
    template<class ...Args>
    struct Visitor;

    template<class CurrentTp>
    struct Visitor<CurrentTp>
    {
      template<class A, class C>
      static void Apply (A &a, C &c)
      {
        auto client = std::dynamic_pointer_cast<CurrentTp> (c);
        if (client and not a.template PeekWithRef<CurrentTp> ())
          a.template PeekWithRef<CurrentTp> () = client;
      }
    };

    template<class CurrentTp, class ...Args>
    struct Visitor<CurrentTp, Args...>
    {
      template<class A, class C>
      static void Apply (A &a, C &c)
      {
        Visitor<CurrentTp>::template Apply (a, c);
        Visitor<Args...>::template Apply (a, c);
      }
    };

  } // namespace injection
} // namespace smunix

namespace smunix
{
  namespace details
  {
    class AggregatorBase
    {
    public:

    protected:
      AggregatorBase()
      {}
      virtual ~AggregatorBase()
      {}
    private:
    }; // class AggregatorBase
  } // namespace details
} // namespace smunix

namespace smunix
{
  namespace details
  {
    template<class K, class I>
    class Resetter
    {
    public:
      typedef Resetter ThisType;
      template<class XY1, class XY2>
      struct Rebind { typedef Resetter<XY1, XY2> Type; };
    public:
      Resetter()
      {}
      virtual ~Resetter()
      {}
    protected:

    private:
    }; // class Resetter

    template<class K, class I>
    class Resetter<std::shared_ptr<K>, I>
    {
      typedef std::shared_ptr<K> ParamType;
      typedef std::shared_ptr<I> ClientType;
    public:
      typedef Resetter ThisType;
      template<class XY1, class XY2>
      struct Rebind { typedef Resetter<XY1, XY2> Type; };
    public:
      Resetter(ParamType p) : mParam (p)
      {}
      virtual ~Resetter()
      {}
      void operator() (ClientType &c)
      {
        c = mParam;
      }
    protected:

    private:
      ParamType mParam;
    }; // class Resetter

    template<class K, class I>
    class Resetter<K *, I>
    {
      typedef K * ParamType;
      typedef std::shared_ptr<I> ClientType;
    public:
      typedef Resetter ThisType;
      template<class XY1, class XY2>
      struct Rebind { typedef Resetter<XY1, XY2> Type; };
    public:
      Resetter(ParamType p) : mParam (p)
      {}
      virtual ~Resetter()
      {}
      void operator() (ClientType &c)
      {
        c.reset (mParam);
      }
    protected:

    private:
      ParamType mParam;
    }; // class Resetter

    template<class I>
    class SwapHelper
    {
    public:
      typedef SwapHelper ThisType;
      template<class K>
      static Resetter<K, I> Reset (K k)
      {
        return Resetter<K, I> (k);
      }
    }; // class SwapHelper

  } // namespace details
} // namespace smunix


#endif /* AGGREGATOR_HPP__222402 */
